package org.objective.dal;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import java.util.UUID;
import org.objective.base.BaseFieldInfo;
import org.objective.base.BaseObjectInfo;
import org.objective.base.BaseTypeInfo;
import org.objective.base.CommonObjectList;
import org.objective.service.Interval;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import org.common.dynamicbean.DynamicBean;
import org.objective.base.CommonObject;
import org.objective.command.CommandResult;
import org.objective.command.RawCommandResult;
import org.objective.service.DalService;

import org.springframework.jdbc.core.ResultSetExtractor;
import static org.utils.fp.collection.CollectionFactory.*;

/**
 *
 * @author gus
 */
class DalServiceImplement implements DalService
{
    public static final String IdNull = "0";
    private JdbcTemplate jdbcTemplate;

    public DalServiceImplement(JdbcTemplate jdbcTemplate)
    {
        this.jdbcTemplate = jdbcTemplate;
    }

    //@Override
    public CommandResult<RowValueCollection> getRowValueCollection(long[] objectIDs, final BeanFactory templateFactory) throws Exception
    {
        ColumnMapper columnMapper = templateFactory.getRowMapper();
        final String query = String.format("SELECT * FROM %s WHERE ID_OBJECT IN ( %s )",
            columnMapper.getTableName(), inClause(objectIDs));

        final Map<Long, DynamicBean> storage = new HashMap<Long, DynamicBean>();

        final DynamicBean template = templateFactory.makeTemplate();
        jdbcTemplate.query(query, new RowMapper()
        {
            @Override
            public Object mapRow(ResultSet rs, int arg1) throws SQLException
            {
                try
                {
                    DynamicBean bean = templateFactory.makeFromResultSet(rs, template);
                    storage.put(bean.<Long>getValue("ID_OBJECT"), bean);
                }
                catch (Exception exc)
                {
                    throw new SQLException("cannot mapped bean", exc);
                }
                return null;
            }
        });
        return new RawCommandResult<RowValueCollection>(new RowValueCollectionImpl(storage));
    }

    private static String inClause(long[] id)
    {
        StringBuilder b = new StringBuilder(IdNull);

        for (int i = 1; i < id.length; i++)
        {
            b.append(", ").append(id[i]);
        }

        return b.toString();
    }

    @Override
    public CommandResult<RowValueCollection> getUserRowValueCollection(BeanFactory rowMapper, Interval interval) throws Exception
    {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public CommandResult<CommonObjectList> getAllObjects(ColumnMapper rowMapper)
    {
        final CommonObjectList list = new CommonObjectList();


        jdbcTemplate.query("", new ResultSetExtractor()
        {
            @Override
            public Object extractData(ResultSet rs) throws SQLException, DataAccessException
            {
                long oid = rs.getLong("OID");
//                list.add(new CommonObject(oid));
                //                list.add(new CommonObject(oid, rs));
                return null;
            }
        });

        rowMapper.getTableName();

        return new RawCommandResult<CommonObjectList>(list);
    }

    @Override
    public CommandResult<Boolean> checkExistType(UUID oid)
    {
        int rowCount = jdbcTemplate.queryForInt("SELECT count(ID_TYPE) FROM METATYPES WHERE OID = ?",
            array(oid.toString()));

        assert rowCount == 1 || rowCount == 0 : "many types";

        return new RawCommandResult<Boolean>(rowCount == 1);
    }

    @Override
    public CommandResult<BaseFieldInfo> loadFieldInfo(long fieldID)
    {
        BaseFieldInfo fieldInfo = (BaseFieldInfo) jdbcTemplate.queryForObject("SELECT * FROM METAFIELDS WHERE ID_FIELD = ?",
            array(fieldID),
            new RowMapper()
            {
                @Override
                public Object mapRow(ResultSet rs, int rowNum) throws SQLException
                {
                    final BaseFieldInfo info = new BaseFieldInfo();
                    info.setId(rs.getLong("ID_FIELD"));
                    info.setName(rs.getString("FIELD_NAME"));
                    info.setDataType(rs.getLong("DATA_TYPE"));
                    info.setObjectRef(rs.getLong("OWNER"));
                    info.setUid(UUID.fromString(rs.getString("OID")));
                    return info;
                }
            });

        return new RawCommandResult<BaseFieldInfo>(fieldInfo);
    }

    @Override
    public CommandResult<BaseObjectInfo> loadObjectInfo(long objectID)
    {
        BaseObjectInfo info = (BaseObjectInfo) jdbcTemplate.queryForObject("", array(objectID),
            new RowMapper()
            {
                @Override
                public Object mapRow(ResultSet rs, int rowNum) throws SQLException
                {
                    throw new UnsupportedOperationException("Not supported yet.");
                }
            });
        return new RawCommandResult<BaseObjectInfo>(info);
    }

    @Override
    public CommandResult<BaseTypeInfo> loadTypeInfo(long typeID)
    {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void insertObject(BaseObjectInfo info) throws Exception
    {
        jdbcTemplate.update("INSERT INTO METAOBJECTS (id_object, objectname, description, oid, owner) " +
            "VALUES (?, ?, ?, ?, ?)",
            array(info.getId(), info.getObjectName(), info.getDescription(), info.getUid().toString(), info.getOwner()));
    }

    @Override
    public void insertType(BaseTypeInfo info) throws Exception
    {
        jdbcTemplate.update("INSERT INTO METATYPES (id_type, typename, description, oid, libraryname) " +
            "VALUES (?, ?, ?, ?, ?)",
            array(info.getId(), info.getName(), info.getDescription(), info.getUID().toString(), info.getLibraryName()));
    }

    @Override
    public CommandResult<Long> getSequenceIDForBaseType()
    {
        long value = jdbcTemplate.queryForLong("SELECT nextval('metatypes_sequence')");
        return new RawCommandResult<Long>(value);
    }

    @Override
    public CommandResult<Long> getSequenceIDForBaseOject()
    {
        long value = jdbcTemplate.queryForLong("SELECT nextval('metaobjects_sequence')");
        return new RawCommandResult<Long>(value);
    }
}

